/*********************************************************************************/
/*                                                                               */
/*      ABZ Driver                                                               */
/*                                                                               */
/*      Last updated by:   CBS                                                   */
/*      Last update date:  13/02/05                                              */
/*      Revision:          0                                                     */
/*      Copyright:         DENSO                                                 */
/*                                                                               */
/*********************************************************************************/
/*********************************************************************************/
/*  include files                                                                */
/*********************************************************************************/
#include "Abz.h"
#include "Abz_Cfg.h"
#include "MPC5674F_MVx264.h"
#include "Std_Types.h"

/*********************************************************************************/
/*  prototypes                                                                   */
/*********************************************************************************/
void Abz_Init(const Abz_ConfigType* ConfigPtr);
void Abz_DeInit(void);
void Abz_StartSignalMeasurement (Abz_ChannelType Channel);
void Abz_StopSignalMeasurement (Abz_ChannelType Channel);
Abz_AnglePositionType Abz_GetAnglePosition(void);
Abz_RotationSpeedType Abz_GetRotationSpeed(void);
void Abz_GetVersionInfo(Std_VersionInfoType* versioninfo);
void Abz_InterruptHandlerA (void);
void Abz_InterruptHandlerZ (void);

/*********************************************************************************/
/*  defines / data types / structs / unions / macros                             */
/*********************************************************************************/
typedef enum {
    ABZ_STATE_UNINITIALIZED, ABZ_STATE_INITIALIZED
}Abz_ModuleStateType; /* module state type definition */

#define Irq_Disable()   asm volatile (" wrteei 0")
#define Irq_Enable()    asm volatile (" wrteei 1")

Abz_ModuleStateType Abz_ModuleState = ABZ_STATE_UNINITIALIZED;   /* module state */
/*********************************************************************************/
/*  constants                                                                    */
/*********************************************************************************/

/*********************************************************************************/
/*  variables                                                                    */
/*********************************************************************************/
static Std_VersionInfoType Abz_VersionInfo ={
    (U2)ABZ_VENDOR_ID, 
    (U2)ABZ_MODULE_ID,
    (U2)ABZ_INSTANCE_ID,
    
    (U1)ABZ_SW_MAJOR_VERSION,
    (U1)ABZ_SW_MINOR_VERSION,
    (U1)ABZ_SW_PATCH_VERSION,
    
    (U1)ABZ_AR_MAJOR_VERSION,
    (U1)ABZ_AR_MINOR_VERSION,
    (U1)ABZ_AR_PATCH_VERSION 
}; /* module version information */

/* current angle position of the rotator*/
Abz_AnglePositionType Abz_AnglePosition = 0; /* LSB:360/4096 Unit:Deg */

/* current rotation speed of the rotator */
Abz_RotationSpeedType Abz_RotationSpeed = 0; /* LSB:1 Unit: rpm */

/* current speed polarity of the rotator */
Abz_SpeedPolarityType Abz_SpeedPolarity = 0;

/* value of last tick */
Abz_TickValueType Abz_LastTickValue = 0;

/* value of current tick */
Abz_TickValueType Abz_CurrentTickValue = 0;

/* value of tick elasped since last interrupt */
Abz_TickValueType Abz_ElapsedTickValue = 0;

/*********************************************************************************/
/*  API Functions                                                                */
/*********************************************************************************/
/*********************************************************************************/
/*  Service name    :   Abz_Init                                                 */
/*  Sync/Async      :   Synchronous                                              */
/*  Reentrancy      :   Non Reentrant                                            */
/*  Parameters (in) :   Pointer to ABZ driver configuration.                     */
/*  Return value    :   None                                                     */
/*  Discription     :   This service initializes the ABZ driver.                 */
/*********************************************************************************/
void Abz_Init(const Abz_ConfigType* ConfigPtr) 
{
    int iterator = 0;

    Irq_Disable();

    for(iterator = 185;iterator < 188; iterator++)
    {
        SIU.PCR[iterator].B.PA = 0x01; 
        SIU.PCR[iterator].B.IBE = 1;
        SIU.PCR[iterator].B.OBE = 0;
    }
    
    /* Enable Module */
    EMIOS.MCR.B.MDIS = (U4)0;
    
    /* Set Global Prescaler */
    EMIOS.MCR.B.GPRE = (U4)ABZ_CLOCK_SCALER;
    
    /* Enable Global Prescaler */
    EMIOS.MCR.B.GPREN = (U4)1;
    
    /* Use global time base */
    EMIOS.MCR.B.GTBE = (U4)1;
    
    memcpy((void*) &EMIOS.CH[ABZ_CHANNEL_A], /* configure Channel A */
        (void*) &ConfigPtr->AbzChannels[0].Abz_ChannelRegister,
        sizeof(Abz_ChannelRegisterType));

    memcpy((void*) &EMIOS.CH[ABZ_CHANNEL_B], /* configure Channel B */
        (void*) &ConfigPtr->AbzChannels[1].Abz_ChannelRegister,
        sizeof(Abz_ChannelRegisterType));

    memcpy((void*) &EMIOS.CH[ABZ_CHANNEL_Z], /* configure Channel Z */
        (void*) &ConfigPtr->AbzChannels[2].Abz_ChannelRegister,
        sizeof(Abz_ChannelRegisterType));

    Abz_ModuleState = ABZ_STATE_INITIALIZED; /* module initialized */
    Irq_Enable();
}

#if ABZ_DE_INIT_API == STD_ON
/*********************************************************************************/
/*  Service name    :   Abz_DeInit                                               */
/*  Sync/Async      :   Synchronous                                              */
/*  Reentrancy      :   Non Reentrant                                            */
/*  Parameters (in) :   None                                                     */
/*  Return value    :   None                                                     */
/*  Discription     :   This service de-initializes the ABZ driver.              */
/*********************************************************************************/
void Abz_DeInit(void)
{
    Irq_Disable();

    EMIOS.MCR.B.MDIS = (U4)1; /* disable module */

    Abz_ModuleState = ABZ_STATE_UNINITIALIZED; /* module unitialized */

    Abz_StopSignalMeasurement (ABZ_CHANNEL_A);
    Abz_StopSignalMeasurement (ABZ_CHANNEL_Z);

    Irq_Enable();
}
#endif /* ABZ_DE_INIT_API */ 

#if ABZ_SIGNAL_MEASUREMENT_API == STD_ON
/*********************************************************************************/
/*  Service name    :   Abz_StartSignalMeasurement                               */
/*  Sync/Async      :   Synchronous                                              */
/*  Reentrancy      :   Reentrant                                                */
/*  Parameters (in) :   Channel ID                                               */
/*  Return value    :   None                                                     */
/*  Discription     :   This service starts the measurement of signals.          */
/*********************************************************************************/
void Abz_StartSignalMeasurement (Abz_ChannelType Channel)
{
    switch(Channel)
    {
        case ABZ_CHANNEL_A :     INTC_InstallINTCInterruptHandler(Abz_InterruptHandlerA,INTC_CHANNEL_A_VectorNum,15);
        case ABZ_CHANNEL_Z :     INTC_InstallINTCInterruptHandler(Abz_InterruptHandlerZ,INTC_CHANNEL_Z_VectorNum,15);
        default: ;
    }

    /* enable interrupt of a specified EMIOS channel */
    EMIOS.CH[Channel].CCR.B.FEN = (U4)1; 

    EMIOS.CH[Channel].CSR.B.FLAG = 1;
}

/*********************************************************************************/
/*  Service name    :   Abz_StopSignalMeasurement                                */
/*  Sync/Async      :   Synchronous                                              */
/*  Reentrancy      :   Reentrant                                                */
/*  Parameters (in) :   Channel ID                                               */
/*  Return value    :   None                                                     */
/*  Discription     :   This service stops the measurement of signals            */
/*********************************************************************************/
void Abz_StopSignalMeasurement (Abz_ChannelType Channel)
{
    /* disable interrupt of a specified EMIOS channel */
    EMIOS.CH[Channel].CCR.B.FEN = (U4)0;    
}
#endif /* ABZ_SIGNAL_MEASUREMENT_API */

#if ABZ_GET_ANGLE_POSITION_API == STD_ON
/*********************************************************************************/
/*  Service name    :   Abz_GetAnglePosition                                     */
/*  Sync/Async      :   Synchronous                                              */
/*  Reentrancy      :   Non Reentrant                                            */
/*  Parameters (in) :   None                                                     */
/*  Return value    :   Angle position                                           */
/*  Discription     :   This service gets the current angle position of the      */
/*                      rotator in the RD converter.                             */
/*********************************************************************************/
Abz_AnglePositionType Abz_GetAnglePosition(void)
{
    return Abz_AnglePosition;
}
#endif /* ABZ_GET_ANGLE_POSITION_API */

#if ABZ_GET_ROTATION_SPEED_API == STD_ON
/*********************************************************************************/
/*  Service name    :   Abz_GetRotationSpeed                                     */
/*  Sync/Async      :   Synchronous                                              */
/*  Reentrancy      :   Non Reentrant                                            */
/*  Parameters (in) :   None                                                     */
/*  Return value    :   Rotation speed                                           */
/*  Discription     :   This service gets the current rotation speed of the      */
/*                      rotator in the RD convertor.                             */
/*********************************************************************************/
Abz_RotationSpeedType Abz_GetRotationSpeed(void)
{
    if((EMIOS.CH[ABZ_CHANNEL_A].CCNTR.R - Abz_LastTickValue) > 500)
    {
        Abz_RotationSpeed = 0;
    }
    return Abz_RotationSpeed;
}
#endif /* ABZ_GET_ROTATION_SPEED_API */

#if ABZ_GET_VERSION_INFO_API == STD_ON
/*********************************************************************************/
/*  Service name    :   Abz_GetVersionInfo                                       */
/*  Sync/Async      :   Synchronous                                              */
/*  Reentrancy      :   Non Reentrant                                            */
/*  Parameters (in) :   Pointer to ABZ driver configuration.                     */
/*  Return value    :   None                                                     */
/*  Discription     :   This service returns the version info of this module.    */
/*********************************************************************************/
void Abz_GetVersionInfo(Std_VersionInfoType* versioninfo)
{
    versioninfo->vendorID = Abz_VersionInfo.vendorID;
    versioninfo->moduleID = Abz_VersionInfo.moduleID;
    versioninfo->instanceID = Abz_VersionInfo.instanceID;
    
    versioninfo->sw_major_version = Abz_VersionInfo.sw_major_version;
    versioninfo->sw_minor_version = Abz_VersionInfo.sw_minor_version;
    versioninfo->sw_patch_version = Abz_VersionInfo.sw_patch_version;
    
    versioninfo->ar_major_version = Abz_VersionInfo.ar_major_version;
    versioninfo->ar_minor_version = Abz_VersionInfo.ar_minor_version;
    versioninfo->ar_patch_version = Abz_VersionInfo.ar_patch_version;
}
#endif/* ABZ_GET_VERSION_INFO_API */

/*********************************************************************************/
/*  Local Functions                                                              */
/*********************************************************************************/
void Abz_InterruptHandlerA ()
{
    EMIOS.CH[ABZ_CHANNEL_A].CSR.B.FLAG = 1;

    /* resolution of 12 bits */
    if(EMIOS.CH[ABZ_CHANNEL_B].CSR.B.UCIN == 0)
    {
        if(Abz_AnglePosition == 4095) /* to prevent overflow */
        {
            Abz_AnglePosition = 0; 
        }
        else
        {
            Abz_AnglePosition++;
        }
        Abz_SpeedPolarity = 1;  /* positive rotation speed */
    }
    else
    {
        if(Abz_AnglePosition == 0) /* to prevent underflow */
        {
            Abz_AnglePosition = 4095;
        }
        else
        {
            Abz_AnglePosition--;
        }
        Abz_SpeedPolarity = 0;  /* positive rotation speed */
    }
}

void Abz_InterruptHandlerZ  ()
{
    EMIOS.CH[ABZ_CHANNEL_Z].CSR.B.FLAG = 1;

    /* reset angle position */
    Abz_AnglePosition = 0; 
    
    /* read current tick from CADR */
    Abz_CurrentTickValue = EMIOS.CH[ABZ_CHANNEL_A].CADR.R; 
    
    /* calculate elapsed tick  */
    Abz_ElapsedTickValue = Abz_CurrentTickValue - Abz_LastTickValue; 
    
    /* calculate rotation speed */
    if(Abz_SpeedPolarity == 1)
    {
        Abz_RotationSpeed = (S4)( 60 * ABZ_SYSTEM_CLOCK / ((ABZ_CLOCK_SCALER + 1) * (ABZ_INTERNAL_PRESCALER + 1)
            * Abz_ElapsedTickValue) + 0.5 ); 
    }
    else
    {
        Abz_RotationSpeed = (S4) (-( 60 * ABZ_SYSTEM_CLOCK / ((ABZ_CLOCK_SCALER + 1) * (ABZ_INTERNAL_PRESCALER + 1)
      * Abz_ElapsedTickValue) + 0.5 )); 
    }
    
    /* update last tick */
    Abz_LastTickValue = Abz_CurrentTickValue;
}
